﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

using SharedGenomics.Core;
using SharedGenomics.Domain;
using SharedGenomics.Domain.Data;
using SharedGenomics.Workbench.Services;
using SharedGenomics.Workbench.Core;
using SharedGenomics.Workbench.Views;
using SharedGenomics.Workbench.Messages;
using SharedGenomics.Workbench.PresentationModel;

namespace SharedGenomics.Workbench.Presenters
{
    public class OpenPhenotypeFilePresenter : TaskStagePresenter<DataFileUploadTaskContext>, IOpenPhenotypeFilePresenter
    {
        private IFileSetUploadService _fileSetUploadService;
        private IFileUpload _fileUpload;
        private FileSetUploadPresentationModel _presentationModel;
        private bool _isFileSetNameValid;
        private bool _isPhenotypeFileValid;

        public OpenPhenotypeFilePresenter(IOpenPhenotypeFileView view, IFileBrowserPresenter fileLoadPresenter, IFileSchemaRepository schemaRepository, ValidationErrorListPresenter validationErrorsPresenter, IFileSetUploadService fileSetUpload, IFileUpload fileUpload)
            : base(view)
        {
            this._presentationModel = new FileSetUploadPresentationModel();
            this._presentationModel.ValidationChanged += new EventHandler<ValidationErrorsNotificationEventArgs>(this.PresentationModel_ValidationChanged);
            view.PresentationModel = this._presentationModel;

            //register for view events
            view.ViewLoaded += (o, e) => { this._presentationModel.Validate(); };
            view.LoadSchemaClicked += new EventHandler(this.View_LoadSchemaClicked);
            view.AddSchemaClicked += new EventHandler(this.View_AddSchemaClicked);
            view.MovePreviousClicked += (o, e) => { this.Task.MovePrevious(); };
            view.UploadClicked += new EventHandler(this.View_UploadClicked);
            view.SelectedFileSchemaChanged += (o, e) => { this.PhenotypeView.IsLoadSchemaEnabled = this.PhenotypeView.SelectedFileSchemaId.HasValue; };

            //set file open prompt text
            fileLoadPresenter.PromptText = "Phenotype file to open:";

            //load button should be disabled until the user opens a phenotype file
            view.IsLoadSchemaEnabled = false;
            view.IsUploadEnabled = false;
            view.IsUploadProgressBarVisisble = false;

            this.PhenotypeView = view;
            this.FileOpen = fileLoadPresenter;
            this.SchemaRepository = schemaRepository;
            this.ValidationErrorsPresenter = validationErrorsPresenter;
            this._fileSetUploadService = fileSetUpload;
            this._fileUpload = fileUpload;
            
            this.FileOpen.FileOpened += new EventHandler(this.FileOpen_FileOpened);
        }

        private void PresentationModel_ValidationChanged(object sender, ValidationErrorsNotificationEventArgs e)
        {
            this._isFileSetNameValid = e.ValidationErrors.IsValid;
            this.View.ValidationErrors = e.ValidationErrors;
            this.SetUploadEnabledState();
        }

        private void View_UploadClicked(object sender, EventArgs e)
        {
            //get the local genotype and phenotype file names
            string localPhenotypeFilePath = this.PhenotypeFilePath;
            string localGenotypeFilePath = this.Task.TaskContext.GenotypeFilePath;
            var genotypeFileFormat = this.Task.TaskContext.GenotypeFileFormat;

            string fileSetName = this._presentationModel.FileSetName;

            this.PhenotypeView.IsMovePreviousEnabled = false;
            this.PhenotypeView.UploadMessage = String.Empty;
            this.PhenotypeView.IsUploadEnabled = true;
            int? schemaId = this.SelectedFileSchemaId;
            Debug.Assert(schemaId.HasValue);

            this.BackgroundExecutor.Execute(() => this._fileSetUploadService.CreateFileSet(fileSetName, schemaId.Value, genotypeFileFormat), or =>
            {
                this.PhenotypeView.IsUploadEnabled = true;
                this.PhenotypeView.IsMovePreviousEnabled = true;
                this.PhenotypeView.IsUploadProgressBarVisisble = false;

                if (or.Error == null)
                {
                    or.Result.BindAction(uploadInfo => 
                    {
                        this._fileUpload.UploadFile(localGenotypeFilePath, uploadInfo.RemoteGenotypeFileUri);
                        this._fileUpload.UploadFile(localPhenotypeFilePath, uploadInfo.RemotePhenotypeFileUri);

                        this.PhenotypeView.UploadMessage = String.Format("File upload for file set '{0}' in progress", fileSetName);
                    });
                }
                else
                {
                    this.PhenotypeView.UploadMessage = String.Format("Error creating file set: {0}", or.Error.Message);
                }
            });
        }

        private void SetUploadEnabledState()
        {
            this.PhenotypeView.IsUploadEnabled = this._isPhenotypeFileValid && this._isFileSetNameValid;
        }

        private void View_AddSchemaClicked(object sender, EventArgs e)
        {
            Action<AddSchemaPresenter> closeAction = p =>
            {
                if (p.SchemaAdded)
                {
                    //TODO: add failure action? It's unlikely the user can logout between these two actions anyway...
                    this.SchemaRepository.GetFileSchemaInfos().BindAction(infos => this.PhenotypeView.AvailableSchemas = infos);
                }
            };

            var openFormMessage = new ShowPresenterMessage(FormDisplayMode.ModalDialog, typeof(AddSchemaPresenter), null, closeAction);
            this.EventBroker.Publish(openFormMessage);
        }

        private void View_LoadSchemaClicked(object sender, EventArgs e)
        {
            int schemaId = this.PhenotypeView.SelectedFileSetInfo.Id;
            this.SchemaRepository.GetSchemaById(schemaId).BindAction(schema =>
            {
                TextDataTableReader reader = new TextDataTableReader(this.PhenotypeFilePath);
                ValidationMessageCollection validationMessages = new ValidationMessageCollection();
                schema.Validate(reader, validationMessages);

                this._isPhenotypeFileValid = validationMessages.ErrorCount == 0;
                this.SetUploadEnabledState();
                this.ValidationErrorsPresenter.ValidationMessages = validationMessages;
            });
        }

        private void FileOpen_FileOpened(object sender, EventArgs e)
        {
            try
            {
                string phenotypeFilePath = this.FileOpen.FilePath;
                if (!this.FileSchemaInfosLoaded)
                {
                    this.SchemaRepository.GetFileSchemaInfos().BindAction(infos =>
                    {
                        this.PhenotypeView.AvailableSchemas = infos;
                        this.FileSchemaInfosLoaded = true;
                    });
                }

                this.PhenotypeFilePath = phenotypeFilePath;
                this.PhenotypeFileLoaded.Raise(this, EventArgs.Empty);
            }
            catch (Exception ex)
            {
                this.View.DisplayError(String.Format("Unable to load phenotype file: {0}", ex.Message));
            }
        }

        private IOpenPhenotypeFileView PhenotypeView { get; set; }

        [Region("FileBrowse")]
        public IFileBrowserPresenter FileOpen { get; private set; }

        [Region("PhenotypeValidationErrors")]
        public ValidationErrorListPresenter ValidationErrorsPresenter { get; private set; }

        private IFileSchemaRepository SchemaRepository { get; set; }

        private bool FileSchemaInfosLoaded { get; set; }

        #region IOpenPhenotypeFilePresenter Members

        public bool Validate(out IValidationErrorCollection errors)
        {
            throw new NotImplementedException();
        }

        public string PhenotypeFilePath { get; private set; }
        public PhenotypeFileInfo PhenotypeInfo
        {
            get { throw new NotImplementedException(); }
        }

        public event EventHandler PhenotypeFileLoaded;

        public int SelectedFileSchemaId
        {
            get
            {
                int? selectedSchemId = this.PhenotypeView.SelectedFileSchemaId;
                ExceptionHelper.ThrowIf<InvalidOperationException>(!selectedSchemId.HasValue, "No file schema Id selected");
                return selectedSchemId.Value;
            }
        }

        #endregion
    }
}
